import threading
import time

import wx
from socket import socket,AF_INET,SOCK_STREAM
class MyServer(wx.Frame):
    def __init__(self, server_name):
        #调用父类的初始化方法
        #None没有父级窗口，id表示当前窗口编号，pos窗体打开位置，size窗体大小，单位像素
        wx.Frame.__init__(self,None,1002,title=server_name+'的服务器端',pos =wx.DefaultPosition,size=(400,450))
        # 创建面板对象
        pl = wx.Panel(self)
        # 在面板上放置盒子
        box = wx.BoxSizer(wx.VERTICAL)  #垂直方向布局
        # 可伸缩的网络布局
        fgz1 = wx.FlexGridSizer(wx.HSCROLL) #水平方向布局
        #创建三个按钮
        start_btn = wx.Button(pl,size=(133,40),label='启动服务')
        save_record_btn = wx.Button(pl,size=(133,40),label='保存聊天记录')
        stop_btn = wx.Button(pl, size=(133, 40), label='停止服务')
        #把按钮放到可伸缩的网络布局
        fgz1.Add(start_btn,0,wx.Top)
        fgz1.Add(save_record_btn,0,wx.TOP)
        fgz1.Add(stop_btn,0,wx.TOP)
        # 把可伸缩的网络布局添加到box中
        box.Add(fgz1,1,wx.ALIGN_CENTER)
        #只读文本框，显示聊天内容
        self.show_text = wx.TextCtrl(pl,size=(400,410),style=wx.TE_MULTILINE|wx.TE_READONLY)
        box.Add(self.show_text,1,wx.CENTER)
        #将盒子放到面板
        pl.SetSizer(box)
        '''-----以上代码是界面绘制代码-----'''
        #以下代码为服务器功能实现的必要属性
        # 存储服务器启动状态
        self.isOn = False
        #创建一个字典，存储与客户端对话的会话线程
        self.session_thread_dict={} #key-value{客户端的名称key：会话线程value}
        #当鼠标点击’启动服务‘按钮时，要执行的操作
        self.Bind(wx.EVT_BUTTON,self.start_server,start_btn)
        #当点击‘保存聊天记录’按钮时，执行相应的操作
        self.Bind(wx.EVT_BUTTON,self.save_chatlog,save_record_btn)
        #‘停止服务’按钮功能
        self.Bind(wx.EVT_BUTTON,self.stop_server,stop_btn)
    def stop_server(self,event):
        print('服务器已停止服务')
        #停止服务
        self.isOn = False
        # 每一个客户端都发送一次
        for client in self.session_thread_dict.values():
            # 判断当前会话是否是开启状态
            if client.isOn:
                client.isOn = False
                client.client_socket.close()
    def start_server(self,event):
        #判断服务器是否启动
        if not self.isOn:
            #启动服务
            print('服务已启动')
            self.isOn = True
            # 服务器端绑定的IP地址和端口,空字符串代表本机所有IP
            self.host_port = ('', 8888)
            # 创建socket对象
            self.server_socket = socket(AF_INET, SOCK_STREAM)
            # 绑定IP地址和端口
            self.server_socket.bind(self.host_port)
            # 监听
            self.server_socket.listen(5)
            #创建主线程对象，函数式创建主线程（继承式也可以）
            main_thread=threading.Thread(target=self.do_work)
            #设置为守护线程，父线程结束（窗体界面）子线程也自动关闭
            main_thread.daemon = True
            #启动主线程
            main_thread.start()
    def do_work(self):
        #判断isOn的值
        while self.isOn:
            #接受客户端的连接请求
            session_socket,client_addr=self.server_socket.accept()
            #客户端发送连接请求后，发送的第一条数据为客户端名称，作为字典中的键
            user_name = session_socket.recv(1024).decode('utf-8')
            print(f'{user_name}连接服务器成功')
            #创建一个会话线程对象
            session_thread=SessionThread(session_socket,user_name,self)
            #存储到字典中
            self.session_thread_dict[user_name]=session_thread
            #启动会话线程
            session_thread.start()
            #输出服务器的提示信息
            self.show_info_and_send_client('服务器通知',f'欢迎{user_name}进入聊天室！',time.strftime('%Y-%m-%d %H:%M:%S',time.localtime()))

        self.server_socket.close()
    def show_info_and_send_client(self,data_source,data,datatime):
        #字符串拼接操作
        send_data = f'{data_source}:{data}\n时间：{datatime}'
        #放到只读文本框
        self.show_text.AppendText('-'*40+'\n'+send_data+'\n')
        #每一个客户端都发送一次
        for client in self.session_thread_dict.values():
            #判断当前会话是否是开启状态
            if client.isOn:
                client.client_socket.send(send_data.encode('utf-8'))
    def save_chatlog(self,event):
        with open('save_record.txt','w+',encoding='utf-8') as file:
            file.write(self.show_text.GetValue())


#服务器会话线程的类
class SessionThread(threading.Thread):
    def __init__(self,client_socket,user_name,server):
        #调用父类的初始化方法
        threading.Thread.__init__(self)
        self.client_socket=client_socket
        self.user_name=user_name
        self.server=server
        #会话线程是否启动
        self.isOn=True
    #run方法中实现与客户端通信
    def run(self):
        while self.isOn:
            #从客户端接受数据，存储到data中
            data = self.client_socket.recv(1024).decode('utf-8')
            #如果客户端点击断开按钮，先给服务器发送一句话，消息自定义
            if data=='---disconnect---':
                self.isOn=False
                self.server.show_info_and_send_client('服务器通知',f'{self.user_name}离开了聊天室',time.strftime('%Y-%m-%d %H:%M:%S',time.localtime()))
            else:
                #其他聊天信息显示给所有的客户端，包含服务器也显示
                self.server.show_info_and_send_client(self.user_name,data,time.strftime('%Y-%m-%d %H:%M:%S',time.localtime()))

        #关闭socket
        self.client_socket.close()


if __name__ == '__main__':
    app = wx.App()
    my_server = MyServer('lf')
    my_server.Show()
    app.MainLoop()
